#include "mainwindow.h"
#include "sortdialog.h"
#include "findDialog.h"
#include "gotocelldialog.h"
#include "spreadsheetcompare.h"
#include <QApplication>
#include <QLabel>
#include <QDebug>
#include <QIcon>
#include <QStatusBar>
#include <QMenuBar>
#include <QFileDialog>
#include <QMessageBox>
#include <QSettings>
#include <QCloseEvent>

QStringList MainWindow::recentFiles;

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent)
{
    spreadsheet = new SpreadSheet;
    setCentralWidget(spreadsheet);
    createActions();
    createMenus();
    createContextMenu();
    createToolBars();
    createStatusBar();
    readSettings();
    findDialog = 0;
    setWindowIcon(QIcon(":/images/icon.png"));
    setCurrentFile("");
    setAttribute(Qt::WA_DeleteOnClose);
}

void MainWindow::closeEvent(QCloseEvent *event)
{
    if (okToContinue()){
        writeSettings();
        event->accept();
    }else{
        event->ignore();
    }
}

void MainWindow::newFile()
{
//    if (okToContinue()){
//        spreadsheet->clear();
//        setCurrentFile("");
//    }
    MainWindow *mainWindow = new MainWindow;
    mainWindow->show();
}

void MainWindow::open()
{
    if (okToContinue()){
        QString fileName = QFileDialog::getOpenFileName(
                    this, tr("Open SpreadSheet"), ".",
                    tr("Spreadsheet files (*.sp)"));
        if (!fileName.isEmpty())
            loadFile(fileName);
    }
}

bool MainWindow::save()
{
    if (curFile.isEmpty()){
        return saveAs();
    }else{
        return saveFile(curFile);
    }
}

bool MainWindow::saveAs()
{
    QString fileName = QFileDialog::getSaveFileName(this,
                       tr("Save SpreadSheet"), ".",
                       tr("spreadsheet files (*.sp)"));
    if (fileName.isEmpty())
        return false;
    return saveFile(fileName);
}

void MainWindow::find()
{
    if (!findDialog){
        findDialog = new FindDialog(this);
        connect(findDialog, SIGNAL(findNext(QString,Qt::CaseSensitivity)),
                spreadsheet, SLOT(findNext(QString,Qt::CaseSensitivity)));
        connect(findDialog, SIGNAL(findPrevious(QString,Qt::CaseSensitivity)),
                spreadsheet, SLOT(findPrevious(QString,Qt::CaseSensitivity)));
    }
    findDialog->show();
    findDialog->raise();
    findDialog->activateWindow();
}

void MainWindow::goToCell()
{
    GoToCellDialog dialog(this);
    if (dialog.exec()){
        QString str = dialog.lineEdit->text().toUpper();
        spreadsheet->setCurrentCell(str.mid(1).toInt()-1,
                                    str[0].unicode() - 'A');
    }
}

void MainWindow::sort()
{
    SortDialog dialog(this);
    QTableWidgetSelectionRange range = spreadsheet->selectedRange();
    dialog.setColumnRange('A'+range.leftColumn(),
                          'A'+range.rightColumn());

    if (dialog.exec()){
        SpreadsheetCompare compare;
        compare.keys[0] = dialog.primaryColumnCombo->currentIndex();
        compare.keys[1] = dialog.secondaryColumnCombo->currentIndex()-1;
        compare.keys[2] = dialog.tertiaryColumnCombo->currentIndex()-1;

        compare.ascending[0] = (dialog.primaryOrderCombo->currentIndex() == 0);
        compare.ascending[1] = (dialog.secondaryColumnCombo->currentIndex() == 0);
        compare.ascending[2] = (dialog.tertiaryColumnCombo->currentIndex() == 0);
        spreadsheet->sort(compare);
    }
}

void MainWindow::about()
{
    QMessageBox::about(this, tr("About SpreadSheet"),
                       tr("<h2>SpreadSheet1.1</h2>"
                          "<p>Copyright &copy; 2014 Software Inc."
                          "<p>SpreadSheet is a small application that"
                          "demonstractes QAction, QMainWindow, QMenuBar,"
                          "QStatusBar, QTableWidget, QToolBar,and many other"
                          "Qt classes."));
}

void MainWindow::openRecentFile()
{
    if (okToContinue()){
        QAction *action = qobject_cast<QAction*>(sender());
        if (action)
            loadFile(action->data().toString());
    }
}

void MainWindow::updateStatusBar()
{
    locationLabel->setText(spreadsheet->currentLocation());
    formulaLabel->setText(spreadsheet->currentFormula());
}

void MainWindow::spreadsheetModified()
{
    setWindowModified(true);
    updateStatusBar();
}

void MainWindow::createActions()
{
    newAction = new QAction(tr("&New"), this);
    newAction->setIcon(QIcon(":/images/new.png"));
    newAction->setShortcut(QKeySequence::New);
    newAction->setStatusTip("Create a new spreadsheet file");
    connect(newAction, SIGNAL(triggered()),
            this, SLOT(newFile()));
    openAction = new QAction(tr("&Open"), this);
    openAction->setIcon(QIcon(":/images/open.png"));
    openAction->setShortcut(QKeySequence::Open);
    openAction->setStatusTip(tr("Open a new spreadsheet file"));
    connect(openAction, SIGNAL(triggered()),
            this, SLOT(open()));

    saveAction = new QAction(tr("&Save"), this);
    saveAction->setIcon(QIcon(":images/save.png"));
    saveAction->setShortcut(QKeySequence::Save);
    saveAction->setStatusTip(tr("Save current spreadsheet file"));
    connect(saveAction, SIGNAL(triggered()),
            this, SLOT(save()));

    saveAsAction = new QAction(tr("&SaveAs"), this);
    saveAsAction->setIcon(QIcon(":images/saveAs.png"));
    saveAsAction->setShortcut(QKeySequence::SaveAs);
    saveAsAction->setStatusTip(tr("Save spreadsheet as a new file"));
    connect(saveAsAction, SIGNAL(triggered()),
            this, SLOT(saveAs()));

    for (int i = 0; i < MaxRecentFiles; ++i){
        recentFileActions[i] = new QAction(this);
        recentFileActions[i]->setVisible(false);
        connect(recentFileActions[i], SIGNAL(triggered()),
                this, SLOT(openRecentFile()));
    }

    exitAction = new QAction(tr("&Exit"), this);
    exitAction->setIcon(QIcon(":images/exit.png"));
    exitAction->setShortcut(tr("Ctrl+Q"));
    exitAction->setStatusTip("Exit the application");
    connect(exitAction, SIGNAL(triggered()),
            qApp, SLOT(closeAllWindows()));

    closeAction = new QAction(tr("&Close"), this);
    closeAction->setShortcut(QKeySequence::Close);
    closeAction->setToolTip(tr("Close the window"));
    connect(closeAction, SIGNAL(triggered()),
            this, SLOT(close()));

    pasteAction = new QAction(tr("&Paste"), this);
    pasteAction->setIcon(QIcon(":images/paste.png"));
    pasteAction->setShortcut(QKeySequence::Paste);
    pasteAction->setStatusTip(tr("Paste"));
    connect(pasteAction, SIGNAL(triggered()),
            spreadsheet, SLOT(paste()));

    copyAction = new QAction(tr("&Copy"), this);
    copyAction->setIcon(QIcon(":images/copy.png"));
    copyAction->setShortcut(QKeySequence::Copy);
    copyAction->setStatusTip(tr("Copy"));
    connect(copyAction, SIGNAL(triggered()),
                spreadsheet, SLOT(copy()));

    cutAction = new QAction(tr("&Cut"), this);
    cutAction->setIcon(QIcon(":images/cut.png"));
    cutAction->setShortcut(QKeySequence::Cut);
    cutAction->setStatusTip(tr("Cut some data"));
    connect(cutAction, SIGNAL(triggered()),
            spreadsheet, SLOT(cut()));

    delAction = new QAction(tr("&Delete"), this);
    delAction->setIcon(QIcon(":images/delete.png"));
    delAction->setShortcut(QKeySequence::Delete);
    delAction->setStatusTip(tr("Cut some cells"));
    connect(delAction, SIGNAL(triggered()),
            spreadsheet, SLOT(del()));

    selectAllAction = new QAction(tr("&All"), this);
    selectAllAction->setShortcut(QKeySequence::SelectAll);
    selectAllAction->setStatusTip(tr("Select all cells in the spreadsheet"));
    connect(selectAllAction, SIGNAL(triggered()),
            spreadsheet, SLOT(selectAll()));

    findAction = new QAction(tr("&Find"), this);
    findAction->setIcon(QIcon(":/images/find.png"));
    findAction->setShortcut(QKeySequence::Find);
    connect(findAction, SIGNAL(triggered()),
            this, SLOT(find()));

    goToCellAction = new QAction(tr("&GotoCell"), this);
    goToCellAction->setShortcut(tr("Ctrl+G"));
    goToCellAction->setStatusTip(tr("Go to a new cell"));
    goToCellAction->setIcon(QIcon(":/images/gotocell.png"));
    connect(goToCellAction, SIGNAL(triggered()),
            this, SLOT(goToCell()));

    selectRowAction = new QAction(tr("&Row"), this);
    selectRowAction->setStatusTip(tr("Select a row"));
    connect(selectRowAction, SIGNAL(triggered()),
            spreadsheet, SLOT(selectCurrentRow()));

    selectColumnAction = new QAction(tr("&Coloumn"), this);
    selectColumnAction->setStatusTip(tr("Select a column"));
    connect(selectColumnAction, SIGNAL(triggered()),
            spreadsheet, SLOT(selectCurrentColumn()));

    aboutAction = new QAction(tr("&About"), this);
    aboutAction->setIcon(QIcon(":/images/about.png"));
    aboutAction->setStatusTip(tr("Show the SpreadSheet information"));
    connect(aboutAction, SIGNAL(triggered()),
            this, SLOT(about()));

    aboutQtAction = new QAction(tr("About &Qt"), this);
    aboutQtAction->setIcon(QIcon(":/images/aboutQt.png"));
    aboutQtAction->setStatusTip(tr("Show the Qt library's About box"));
    connect(aboutQtAction, SIGNAL(triggered()),
            qApp, SLOT(aboutQt()));

    showGridAction = new QAction(tr("&Show Grid"), this);
    showGridAction->setIcon(QIcon(":/images/showGrid.png"));
    showGridAction->setCheckable(true);
    showGridAction->setChecked(true);
    showGridAction->setStatusTip(tr("Show or hide the spreadsheet's grid"));
    connect(showGridAction, SIGNAL(toggled(bool)),
            spreadsheet, SLOT(setShowGrid(bool)));

    autoRecalculateAction = new QAction(tr("&Auto-Recalculate"),this);
    autoRecalculateAction->setCheckable(true);
    autoRecalculateAction->setChecked(true);
    autoRecalculateAction->setStatusTip(tr("Auto recalculate or not?"));
    connect(autoRecalculateAction, SIGNAL(toggled(bool)),
            spreadsheet, SLOT(setAutoRecalculate(bool)));

    recalculateAction = new QAction(tr("&Recalculate"), this);
    // setting shortcut ---> F9 ?
    //recalculateAction->setShortcut(QKeySequence::);
    recalculateAction->setToolTip(tr("Recalculate the spreadsheet"));
    connect(recalculateAction, SIGNAL(triggered()),
            spreadsheet, SLOT(recalculate()));

    sortAction = new QAction(tr("&Sort"), this);
    sortAction->setShortcut(tr("Ctrl+S"));
    sortAction->setIcon(QIcon(":/images/sort.png"));
    connect(sortAction, SIGNAL(triggered()),
            this, SLOT(sort()));

}

void MainWindow::createMenus()
{
    fileMenu = menuBar()->addMenu(tr("&File"));
    fileMenu->addAction(newAction);
    fileMenu->addAction(openAction);
    fileMenu->addAction(saveAction);
    fileMenu->addAction(saveAsAction);
    separatorAction = fileMenu->addSeparator();
    for (int i = 0; i < MaxRecentFiles; ++i)
        fileMenu->addAction(recentFileActions[i]);
    fileMenu->addSeparator();
    fileMenu->addAction(closeAction);
    fileMenu->addAction(exitAction);

    editMenu = menuBar()->addMenu(tr("&Edit"));
    editMenu->addAction(cutAction);
    editMenu->addAction(copyAction);
    editMenu->addAction(pasteAction);
    editMenu->addAction(delAction);

    selectSubMenu = editMenu->addMenu(tr("&Select"));
    selectSubMenu->setIcon(QIcon(":/images/select.png"));
    selectSubMenu->addAction(selectRowAction);
    selectSubMenu->addAction(selectColumnAction);
    selectSubMenu->addAction(selectAllAction);

    editMenu->addSeparator();
    editMenu->addAction(findAction);
    editMenu->addAction(goToCellAction);



    toolsMenu = menuBar()->addMenu(tr("&Tools"));
    toolsMenu->addAction(recalculateAction);
    toolsMenu->addAction(sortAction);

    optionsMenu = menuBar()->addMenu(tr("&Options"));
    optionsMenu->addAction(showGridAction);
    optionsMenu->addAction(autoRecalculateAction);

    menuBar()->addSeparator();

    helpMenu = menuBar()->addMenu(tr("&Help"));
    helpMenu->addAction(aboutAction);
    helpMenu->addAction(aboutQtAction);
}

void MainWindow::createContextMenu()
{
    spreadsheet->addAction(cutAction);
    spreadsheet->addAction(copyAction);
    spreadsheet->addAction(pasteAction);
    spreadsheet->addAction(sortAction);

    spreadsheet->setContextMenuPolicy(Qt::ActionsContextMenu);

}

void MainWindow::createToolBars()
{
    fileToolBar = addToolBar(tr("&File"));
    fileToolBar->addAction(newAction);
    fileToolBar->addAction(openAction);
    fileToolBar->addAction(saveAction);

    editToolBar = addToolBar(tr("&Edit"));
    editToolBar->addAction(cutAction);
    editToolBar->addAction(copyAction);
    editToolBar->addAction(pasteAction);
    editToolBar->addSeparator();
    editToolBar->addAction(findAction);
    editToolBar->addAction(goToCellAction);
}

void MainWindow::createStatusBar()
{
    locationLabel = new QLabel(" W999 ");
    locationLabel->setAlignment(Qt::AlignHCenter);
    locationLabel->setMinimumSize(locationLabel->sizeHint());

    formulaLabel = new QLabel;
    formulaLabel->setIndent(3);

    statusBar()->addWidget(locationLabel);
    statusBar()->addWidget(formulaLabel, 1);

    connect(spreadsheet, SIGNAL(currentCellChanged(int,int,int,int)),
            this, SLOT(updateStatusBar()));
    connect(spreadsheet, SIGNAL(modified()),
            this, SLOT(spreadsheetModified()));
    updateStatusBar();
}

void MainWindow::readSettings()
{
    QSettings settings("Software Inc.","Spreadsheet");

    restoreGeometry(settings.value("geometry").toByteArray());
    recentFiles = settings.value("recentFiles").toStringList();
    foreach (QWidget *win, QApplication::topLevelWidgets()) {
        if (MainWindow *mainWin = qobject_cast<MainWindow *>(win))
            mainWin->updateRecentFileActions();
    }
    bool showGrid = settings.value("showGrid", true).toBool();
    foreach (QWidget *win, QApplication::topLevelWidgets()) {
        if (MainWindow *mainWin = qobject_cast<MainWindow *>(win))
            mainWin->showGridAction->setChecked(showGrid);
    }

    bool autoRecalc = settings.value("autoRecalc", true).toBool();
    foreach (QWidget *win, QApplication::topLevelWidgets()) {
        if (MainWindow *mainWin = qobject_cast<MainWindow *>(win))
            mainWin->autoRecalculateAction->setChecked(autoRecalc);
    }
}

void MainWindow::writeSettings()
{
    QSettings settings("Software Inc.", "Spreadsheet");

    settings.setValue("geometry", saveGeometry());
    settings.setValue("recentFiles", recentFiles);
    settings.setValue("showGrid", showGridAction->isChecked());
    settings.setValue("autoRecalc", autoRecalculateAction->isChecked());
}

bool MainWindow::okToContinue()
{
    if (isWindowModified()){
        int r = QMessageBox::warning(this, tr("SpreadSheet"),
                tr("The document has been modified.\n"
                   "Do you want to save your changes?"),
                QMessageBox::Yes|QMessageBox::No|QMessageBox::Cancel);
        if (r == QMessageBox::Yes){
            return save();
        }else if (r == QMessageBox::Cancel){
            return false;
        }
    }
    return true;
}

bool MainWindow::loadFile(const QString &fileName)
{
    if (!spreadsheet->readFile(fileName)){
        statusBar()->showMessage(tr("Loading cancled"), 2000);
        return false;
    }

    setCurrentFile(fileName);
    statusBar()->showMessage(tr("File loaded"), 2000);
    return true;
}

bool MainWindow::saveFile(const QString &fileName)
{
    if (!spreadsheet->writeFile(fileName)){
        statusBar()->showMessage(tr("Saving cancled"), 2000);
        return false;
    }

    setCurrentFile(fileName);
    statusBar()->showMessage(tr("File saved"), 2000);
    return true;
}

void MainWindow::setCurrentFile(const QString &fileName)
{
    curFile = fileName;
    setWindowModified(false);
    QString showName = tr("Untitled");
    if (!curFile.isEmpty()){
        showName = strippedName(curFile);
        recentFiles.removeAll(curFile);
        recentFiles.prepend(curFile);
        foreach (QWidget *win, QApplication::topLevelWidgets()) {
            if (MainWindow *mainWin = qobject_cast<MainWindow *>(win))
                mainWin->updateRecentFileActions();
        }
    }
    setWindowTitle(tr("%1[*] - %2").arg(showName)
                   .arg(tr("Spreadsheet")));
}

void MainWindow::updateRecentFileActions()
{
    QMutableStringListIterator i(recentFiles);
    while (i.hasNext()){
        if (!QFile::exists(i.next()))
            i.remove();
    }

    for (int j = 0; j < MaxRecentFiles; ++j){
        if (j < recentFiles.count()){
            QString text = tr("&%1 %2").arg(j+1)
                    .arg(strippedName(recentFiles[j]));
            recentFileActions[j]->setText(text);
            recentFileActions[j]->setData(recentFiles[j]);
            recentFileActions[j]->setVisible(true);
        }else{
            recentFileActions[j]->setVisible(false);
        }
    }
    separatorAction->setVisible(!recentFiles.isEmpty());
}

QString MainWindow::strippedName(const QString &fullName)
{
    return QFileInfo(fullName).fileName();
}
